package com.navi.loaddata.loadService.impl.mesData.glassData;

import com.alibaba.fastjson.JSONObject;
import com.navi.loaddata.core.errorLog.ErrorCode;
import com.navi.loaddata.core.etlException.ETLException;
import com.navi.loaddata.core.etlException.ETLException2;
import com.navi.loaddata.core.gpEntity.File.FileGlassPojo;
import com.navi.loaddata.core.mysqlEntity.EtlConfD;
import com.navi.loaddata.core.mysqlEntity.EtlConfDDefect;
import com.navi.loaddata.core.mysqlEntity.EtlConfDModel;
import com.navi.loaddata.core.util.JacksonUtil;
import com.navi.loaddata.core.util.JdbcUtil;
import com.navi.loaddata.core.util.LoggerUtil;
import com.navi.loaddata.loadService.impl.mesData.LoadMESDataBean;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.sql.SQLRecoverableException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class LoadMESGlassService {
    private static final Logger logger = LoggerFactory.getLogger(LoadMESGlassService.class);
    @Autowired
    private AmqpTemplate rabbitTemplate;
    @Autowired
    private LoadMESGlassInfoService loadMESGlassInfoService;
    @Autowired
    private LoadMESDataBean loadMESDataBean;

    @Autowired
    private JedisPool jedisPool;

    public String[] loadMESGlassDataMain(EtlConfDModel etlConfD) throws Exception {
        String[] resMsg = loadMESGlass(etlConfD);
        logger.info("loadMESGlassDataMain finish");
        return resMsg;
    }

    private String[] loadMESGlass(EtlConfDModel etlConfD) throws Exception {
        String[] resMsg = new String[3];
        int okCnt = 0;
        int errCnt = 0;
        String errMsg = null;

        List<FileGlassPojo> defectCntList = new ArrayList<>();
        List<FileGlassPojo> glassInfoList = new ArrayList<>();

        try {
            defectCntList = loadMESGlassInfoService.getMESGlassDefectCnt(etlConfD);
            glassInfoList = loadMESGlassInfoService.getMESGlassInfo(etlConfD);
        } catch (SQLRecoverableException e) {
            logger.error("报错信息：" + LoggerUtil.stackTraceToString(e));
            etlConfD.setRunFlg("N");
            loadMESGlassInfoService.updateEtlConfD(etlConfD);

            resMsg[0] = String.valueOf(okCnt);
            resMsg[1] = String.valueOf(errCnt);
            resMsg[2] = errMsg;

            return resMsg;
        }

        logger.info("MES Glass 共{}笔数据", glassInfoList.size());

        if (!glassInfoList.isEmpty()) {
            //给Glass的glass_defect_cnt栏位赋值
            if (!defectCntList.isEmpty()) {
                for (FileGlassPojo defectCnt : defectCntList) {
                    for (FileGlassPojo glassInfo : glassInfoList) {
                        //若evt_timestamp、ope_id、glass_id一致，则把汇总的defect数量赋值给glass信息的glass_defect_cnt栏位
                        if (defectCnt.getEvtTimestamp().equals(glassInfo.getEvtTimestamp()) && defectCnt.getOpeId().equals(glassInfo.getOpeId())
                                && defectCnt.getGlassId().equals(glassInfo.getGlassId())) {
                            glassInfo.setGlassDefectCnt(defectCnt.getGlassDefectCnt());
                            break;
                        }
                    }
                }
            }

            for (FileGlassPojo glassInfo : glassInfoList) {
                try {
                    //Rabbit MQ需要给ope_tbl_name的值（表名）
                    glassInfo.setOpe_tbl_name("wpp_cdefect_glass_f");

                    String opeId = etlConfD.getOpe();
                    String glassId = glassInfo.getGlassId();
                    String evtTimestamp = glassInfo.getEvtTimestamp();

                    //设定存redis的key为opeId+glassId+evtTimestamp
                    String glassKey = String.format("RPT_GLASS:opeId:%s glassId:%s", opeId, glassId);

                    String value = "";
                    String newValue = "";

                    try (Jedis jedis = jedisPool.getResource()) {
                        value = jedis.get(glassKey);

                        if (value == null || value.length() == 0) {
                            newValue = glassInfo.getJgeCnt() + "_" + evtTimestamp;
                            glassInfo.setRealFlg("Y");
                        } else {
                            SimpleDateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                            //匹配evt_timestamp是否大于redis记录的时间，若大于，说明为正常跑数据，记录新的evt_timestamp且jge_cnt加1，redis记录evt_timestamp时间不变，若小于或等于，说明是数据重跑
                            if (dt.parse(evtTimestamp).compareTo(dt.parse(value.substring(value.indexOf("_") + 1))) > 0) {
                                newValue = glassInfo.getJgeCnt() + "_" + evtTimestamp;
                                //ope_id、glass_id相同，而evt_timestamp不同，说明做了重工，前一笔数据的real_flg需置为N
                                String oldEvtTimestamp = value.substring(value.indexOf("_")+1);
                                updateRealFlg(opeId.substring(1,opeId.length()), glassId, oldEvtTimestamp, value.substring(0, value.indexOf("_")));
                                glassInfo.setRealFlg("Y");
                            } else if (dt.parse(evtTimestamp).compareTo(dt.parse(value.substring(value.indexOf("_") + 1))) == 0) {
                                newValue = value;
                                glassInfo.setRealFlg("Y");
                            } else {
                                newValue = value;
                                glassInfo.setRealFlg("N");
                            }
                        }

                        //在redis里记录新的jge_cnt和evt_timestamp值
                        jedis.set(glassKey, newValue);
                        jedis.expire(glassKey, 15552000); // 设置过期时间为6个月
                    } catch (Exception e) {
                        logger.error(LoggerUtil.stackTraceToString(e));
                        logger.error("************   Redis Insert Error  **********    " + glassInfo.getOpeId() + " " + glassInfo.getGlassId() + " " + newValue);
                    }

                    //etl_timestamp赋值
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Timestamp nowTimestamp = Timestamp.valueOf(dateFormat.format(new Date()));
                    String nowTimestampStr = nowTimestamp.toString();
                    glassInfo.setEtlTimestamp(nowTimestampStr);

                    //glass信息中的ope_id保留后4位
                    glassInfo.setOpeId(glassInfo.getOpeId().substring(1, glassInfo.getOpeId().length()));

                    //shf_id,hour_id,cald_date等赋值
                    loadMESDataBean.setGlassHourSht(glassInfo);

                    //将glass数据抛给Rabbit MQ
                    saveMesGlass(glassInfo);

                    logger.info("glassId={} opeId={} jgeCnt={}保存成功。",
                            glassInfo.getGlassId(), glassInfo.getOpeId(), glassInfo.getJgeCnt());
                    okCnt++;
                } catch (ETLException2 e) {
                    String err = e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    logger.error("opeId={} glassId={} {}-{} {},错误原因：{}",
                            glassInfo.getOpeId(), glassInfo.getGlassId(), etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp(), e.getErrorCode().getErrorMsg(), LoggerUtil.stackTraceToString(e));
                    if (StringUtils.isEmpty(err)) {
                        errMsg = "opeId=" + glassInfo.getOpeId() + " " + "glassId=" + glassInfo.getGlassId() + " " + err + "\n";
                    } else {
                        errMsg += "opeId=" + glassInfo.getOpeId() + " " + "glassId=" + glassInfo.getGlassId() + " " + err + "\n";
                    }
                    errCnt++;
                } catch (Exception e) {
                    String err = LoggerUtil.stackTraceToString(e);
                    logger.error("opeId={} glassId={} {}-{} 保存错误，错误原因：{}",
                            glassInfo.getOpeId(), glassInfo.getGlassId(), etlConfD.getRunStartTimestamp(), etlConfD.getRunEndTimestamp(), err);
                    if (StringUtils.isEmpty(err)) {
                        errMsg = "opeId=" + glassInfo.getOpeId() + " " + "glassId=" + glassInfo.getGlassId() + " " + err + "\n";
                    } else {
                        errMsg += "opeId=" + glassInfo.getOpeId() + " " + "glassId=" + glassInfo.getGlassId() + " " + err + "\n";
                    }
                    errCnt++;
                }
            }
        } else {
            logger.info("没有此区间的数据。"); // todo print log & save etl data
        }
        resMsg[0] = String.valueOf(okCnt);
        resMsg[1] = String.valueOf(errCnt);
        resMsg[2] = errMsg;

        return resMsg;
    }


    public void saveMesGlass(FileGlassPojo glassInfo) throws Exception {
        try {
            rabbitTemplate.convertAndSend("qmsExchange", "C_GLASS", JacksonUtil.toJSONStr(glassInfo));
        } catch (Exception e) {
            logger.error(LoggerUtil.stackTraceToString(e));
            throw new ETLException2(ErrorCode.ERROR_RABBITMQ_MES_GLASS, e);
        }
    }

    public void updateRealFlg(String opeId, String glassId, String oldEvtTimestamp, String jgeCnt) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Timestamp nowTimestamp = Timestamp.valueOf(dateFormat.format(new Date()));

        String nowTimestampStr = nowTimestamp.toString();

        JSONObject update_columns = new JSONObject();
        update_columns.put("real_flg", "N");
        update_columns.put("etl_timestamp", nowTimestampStr);

        JSONObject query_conditions = new JSONObject();
        query_conditions.put("glass_id", glassId);
        query_conditions.put("ope_id", opeId);
        query_conditions.put("jge_cnt", jgeCnt);
        query_conditions.put("real_flg", "Y");
        query_conditions.put("evt_timestamp", oldEvtTimestamp);

        JSONObject updateJsonObj = new JSONObject();
        updateJsonObj.put("update_flg", "true");
        updateJsonObj.put("ope_tbl_name", "wpp_cdefect_glass_f");
        updateJsonObj.put("query_conditions", query_conditions);
        updateJsonObj.put("update_columns", update_columns);

        try {
            rabbitTemplate.convertAndSend("qmsExchange", "C_GLASS", JacksonUtil.toJSONStr(updateJsonObj));
        } catch (Exception e) {
            logger.error(LoggerUtil.stackTraceToString(e));
            throw new ETLException2(ErrorCode.ERROR_RABBITMQ_GP_REALFLG, e);
        }
    }

    //获取LoadMESDefectData在etl_conf_d的数据
    public List<EtlConfDDefect> getMESDefectJob() {
        List<EtlConfDDefect> etlConfDList = new ArrayList<EtlConfDDefect>();
        QueryRunner qr_mysql = JdbcUtil.getQueryRunner_mysql();

        String hisJobFlagSql = "select RUN_START_TIMESTAMP,QUERY_MINUTE from ch_qms.etl_conf_d" +
                " where job_group_name = 'RPT_ETL_MES'" +
                " and job_name = 'LoadMESDefectData'";

        try {
            etlConfDList = qr_mysql.query(hisJobFlagSql, new BeanListHandler<EtlConfDDefect>(EtlConfDDefect.class));  //获取etl_conf_d表中his job的ext_2，作为current job的run job的参考
        } catch (Exception e) {
            logger.error(LoggerUtil.stackTraceToString(e));
            try {
                throw new ETLException("ERROR get MESDefectJob data!" + LoggerUtil.stackTraceToString(e));
            } catch (ETLException e1) {
                e1.printStackTrace();
            }

        }

        return etlConfDList;
    }
}
